﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using AutoTest.Common.UtilsHelper;

namespace AutoTest.Common.Extension
{
    /// <summary>
    /// 集合扩展方法
    /// </summary>
    public static class CollectionExtension
    {

        /// <summary>
        /// 根据约束
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="equalExpression"></param>
        /// <returns></returns>
        public static bool Contains<T>(this IEnumerable<T> source, Func<T, bool> equalExpression)
        {
            return source.Any(item => equalExpression(item));
        }

        /// <summary>
        /// 集合是否为空或者null
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsEmpty<T>(this IEnumerable<T> source)
        {
            return !IsNotEmpty(source);
        }

        /// <summary>
        /// 判断集合是否非空
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsNotEmpty<T>(this IEnumerable<T> source)
        {
            return source?.Any() ?? false;
        }

        /// <summary>
        /// 合并多个字典到第一个字段
        /// </summary>
        /// <typeparam name="TKey">字典的key</typeparam>
        /// <typeparam name="TValue">字典的值</typeparam>
        /// <param name="dict">字典</param>
        /// <param name="conver">key存在是否覆盖</param>
        /// <param name="dicts">后续的字典集合</param>
        /// <returns></returns>
        public static Dictionary<TKey, TValue> MergeDict<TKey, TValue>(this Dictionary<TKey, TValue> dict, bool conver, params Dictionary<TKey, TValue>[] dicts) where TKey : notnull
        {
            #region merge dict

            foreach (var d in dicts)
            {
                foreach (var item in d)
                {
                    if (dict.ContainsKey(item.Key))
                    {
                        if (conver) dict[item.Key] = item.Value;
                    }
                    else
                    {
                        dict.Add(item.Key, item.Value);
                    }
                }

            }

            #endregion

            return dict;
        }

        /// <summary>
        /// 获取字典的数据，没有Key则返回默认值
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="dict"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static TValue GetDictValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key) where TKey : notnull
        {
            if (dict?.ContainsKey(key) ?? false)
            {
                return dict[key];
            }
            return default!;
        }

        /// <summary>
        /// 遍历集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="action"></param>
        public static void Foreach<T>(this IEnumerable<T> source, Action<T> action)
        {
            if (source.IsNotEmpty())
            {
                foreach (var item in source)
                {
                    action(item);
                }
            }
        }

        /// <summary>
        /// 如果不存在，就添加
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="source">列表</param>
        /// <param name="value">值</param>
        public static void AddIfNotContain<T>(this ICollection<T> source, T value)
        {
            if (!source.Contains(value))
            {
                source.Add(value);
            }
        }

        /// <summary>
        /// 如果不存在，就添加
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="source">列表</param>
        /// <param name="value">值</param>
        /// <param name="equalExpression">存在条件</param>
        public static void AddIfNotContain<T>(this ICollection<T> source, T value, Func<T, bool> equalExpression)
        {
            if (!source.Contains(equalExpression))
            {
                source.Add(value);
            }
        }

        /// <summary>
        /// 自定义Distinct扩展方法
        /// </summary>
        /// <typeparam name="T">要去重的对象类</typeparam>
        /// <typeparam name="C">自定义去重的字段类型</typeparam>
        /// <param name="source">要去重的对象</param>
        /// <param name="getfield">获取自定义去重字段的委托</param>
        /// <returns></returns>
        public static IEnumerable<T> DistinctObj<T, C>(this IEnumerable<T> source, Func<T, C> getfield)
        {
            return source.Distinct(new Compare<T, C>(getfield));
        }

        /// <summary>
        /// 数组组合成字符串
        /// </summary>
        /// <typeparam name="T">数组泛型</typeparam>
        /// <param name="source">数组列表</param>
        /// <param name="seperate">连接的字符串</param>
        /// <returns></returns>
        public static string StrJoin<T>(this IEnumerable<T> source, string seperate)
        {
            return string.Join(seperate, source);
        }

        /// <summary>
        /// 同步分页执行
        /// </summary>
        /// <typeparam name="ParamT"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="paramsList"></param>
        /// <param name="threadExcute"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public static List<T> PageExcute<ParamT, T>(this List<ParamT> paramsList, Func<List<ParamT>, T> excute, int pageSize = 1000)
        {
            return CollectionHelper.PageExcute(paramsList,excute, pageSize);
        }

        /// <summary>
        /// 同步分页执行
        /// </summary>
        /// <typeparam name="ParamT">参数对象</typeparam>
        /// <typeparam name="T">返回对象</typeparam>
        /// <param name="paramsList">数组列表</param>
        /// <param name="threadExcute">执行方法</param>
        /// <param name="pageSize">分页数量</param>
        /// <returns></returns>
        public static async Task<List<T>> PageExcuteAsync<ParamT, T>(this List<ParamT> paramsList, Func<List<ParamT>, Task<T>> tasExcuteAsync, int pageSize = 1000)
        {
            return await CollectionHelper.PageExcuteAsync(paramsList, tasExcuteAsync, pageSize);
        }

        /// <summary>
        /// 多线程执行
        /// </summary>
        /// <typeparam name="ParamT"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="paramsList"></param>
        /// <param name="threadExcute">线程执行方法</param>
        /// <param name="maxThread">最大线程数</param>
        /// <param name="threadDealSize">每个线程处理数量</param>
        /// <returns></returns>
        public static async Task<List<T>> ThreadPageExcuteAsync<ParamT, T>(this List<ParamT> paramsList, Func<List<ParamT>, T> threadExcute, int maxThread, int threadDealSize = 10000)
        {
            return await CollectionHelper.ThreadPageExcuteAsync(paramsList, threadExcute, maxThread, threadDealSize);
        }

        /// <summary>
        /// 多线程异步执行
        /// </summary>
        /// <typeparam name="ParamT"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="filterLis"></param>
        /// <param name="threadQueryActionAsync"></param>
        /// <param name="maxThread"></param>
        /// <param name="threadDealSize"></param>
        /// <returns></returns>
        public static async Task<List<T>> ThreadPageExcuteAsync<ParamT, T>(List<ParamT> paramsList, Func<List<ParamT>, Task<List<T>>> threadExcuteAsync, int maxThread, int threadDealSize = 10000)
        {
            return await CollectionHelper.ThreadPageExcuteAsync(paramsList, threadExcuteAsync, maxThread, threadDealSize);
        }
    }

    /// <summary>
    /// 比较
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="C"></typeparam>
    /// <remarks>
    /// 比较字段
    /// </remarks>
    /// <param name="getfield"></param>
    public class Compare<T, C>(Func<T, C> getfield) : IEqualityComparer<T>
    {
        private readonly Func<T, C> _getField = getfield;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public bool Equals(T? x, T? y) => EqualityComparer<C>.Default.Equals(_getField(x!), _getField(y!));
        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public int GetHashCode(T obj)
        {
            var v = _getField(obj);
            return EqualityComparer<C>.Default.GetHashCode(v ?? default!);
        }
    }
}
